package controllers.GestionTratamientoDatos.Metodos.Completacion.Metodos;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;

import controllers.GestionTratamientoDatos.Metodos.Completacion.MetodoCompletacionBase;
import models.Hidregistro;
import org.ejml.simple.SimpleMatrix;


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 * Cubic spline para completar datos de una serie faltante
 * FALTA CONSIDERAR DATOS CON INICIOS NULOS O TERMINACIONES NULAS
 */

/**
 *
 * @author ALICIA
 */

public class cubicSplineH extends MetodoCompletacionBase{


    public final static int sizz= 200;
    public Vector<Vector<Double>> H; //INDICES no valores  de los intervalos
    public Double [][] coefmat ;
    public SimpleMatrix sm;
    public Double [] ymat;
    public SimpleMatrix ymat2;
    public SimpleMatrix sn;
    public SimpleMatrix S;
    public Vector<Double> result;

    public cubicSplineH (Vector<Double> v){
        super(v);
    }

    @Override
    public void completar(){

        //cubicSplineH matH = new cubicSplineH();
        H = new Vector<Vector<Double>>();

        System.out.println("VECTOR DE LA CLASE CUBIC "+ getSerieVector());
        genInterval(getSerieVector());
        initCoefMat();
        fillCoefMat();
        initYMat(getSerieVector());
        initSn();
        initS(getSerieVector());
        getResult(getSerieVector());

        System.out.println("SALIDA DE CLASE CUBIC   "+getResult());
        setSerieVector(getResult());
    }



    public Vector<Double> getResult() {
        return result;
    }

    public void setResult(Vector<Double> result) {
        this.result = result;
    }

    public Vector<Vector<Double>> getH() {
        return H;
    }

    public void setH(Vector<Vector<Double>> H) {
        this.H = H;
    }

    public SimpleMatrix getYmat2() {
        return ymat2;
    }

    public SimpleMatrix getSm() {
        return sm;
    }

    public void setSm(SimpleMatrix sm) {
        this.sm = sm;
    }

    public SimpleMatrix getSn() {
        return sn;
    }

    public void setSn(SimpleMatrix sn) {
        this.sn = sn;
    }

    public void setYmat2(SimpleMatrix ymat2) {
        this.ymat2 = ymat2;
    }

    public Double[][] getCoefmat() {
        return coefmat;
    }

    public Double[] getYmat() {
        return ymat;
    }

    public void setYmat(Double[] ymat) {
        this.ymat = ymat;
    }

    public void setCoefmat(Double[][] coefmat) {
        this.coefmat = coefmat;
    }

    public SimpleMatrix getS() {
        return S;
    }

    public void setS(SimpleMatrix S) {
        this.S = S;
    }




    /*public cubicSplineH() {

        H=new Vector<Vector<Double>>();
    } */

    public  void genInterval(Vector<Double> data)
    {
        Integer count=0;
        Double num=999999.0;
        Integer count2=1;
        //System.out.println("entre..");
        while(count<data.size())
        {
            //System.out.println(data.get(count));
            if((data.get(count)!=999999)){// Float.isNaN(f);

                if(num==999999)
                {
                    num=count.doubleValue();
                }

                else
                {
                    Vector<Double> row = new Vector<Double>();
                    row.add(num);                 // numero a1
                    row.add(count.doubleValue()); //numero a2
                    row.add(count-num);  //tamaño de intervalo
                    num=count.doubleValue();
                    H.add(row);
                    //System.out.println("h:"+H);
                    //count2++;

                }
            }
            count++;

        }
        //return H;
    }
    public void initCoefMat()
    {
        coefmat = new Double[H.size()-1][H.size()-1];
        for(Double[] row: coefmat)
        {
            Arrays.fill(row, 0.0);
        }
    }
    public void initYMat(Vector<Double> dat)
    {
        ymat = new Double[coefmat.length];
        ymat2= new SimpleMatrix(coefmat.length+1,1);
        for(int l=1;l<H.size();l++)
        {  // System.out.println("entre..initYMat");
            ymat[l-1]=6*((dat.get((H.get(l).get(1)).intValue()) - dat.get(H.get(l).get(0).intValue()))/(H.get(l).get(2)).doubleValue()-
                    (dat.get((H.get(l).get(0)).intValue()) - dat.get(H.get(l-1).get(0).intValue()))/(H.get(l-1).get(2).doubleValue()));
            ymat2.set(l-1,0,ymat[l-1]);
        }
        ymat2.set(ymat2.numRows()-1, 0, 0.0);


    }
    public void fillCoefMat()
    {
        coefmat[0][0]=2*(H.get(0).get(2)+H.get(1).get(2));
        coefmat[0][1]=H.get(1).get(2);

        coefmat[coefmat.length-1][coefmat.length-1]=2*(H.get(H.size()-1).get(2)+ H.get(H.size()-2).get(2));
        //System.out.println("entre..");
        coefmat[coefmat.length-1][coefmat.length-2]=H.get(H.size()-1).get(2);

        int countcoef=0;

        for(int r=1;r<coefmat.length-1;r++)
        {
            coefmat[r][countcoef]=H.get(r).get(2);
            coefmat[r][countcoef+1]=2*( H.get(r).get(2) + H.get(r+1).get(2));
            coefmat[r][countcoef+2]=H.get(r+1).get(2);
            countcoef++;

        }
        this.arrayToSimpleM();

    }
    public void initSn()
    {       sn=new SimpleMatrix(coefmat.length,1);
        SimpleMatrix sm2= new SimpleMatrix(sm.numRows()+1,sm.numCols()+1);
        this.lastCero(sm2, sm.invert());

        sn=sm2.mult(ymat2);


    }
    public void initS(Vector<Double> dat)
    {
        S= new SimpleMatrix(coefmat.length, 4);
        for(int i=0;i<coefmat.length;i++)
        {
            S.set(i, 0,(sn.get(i+1, 0)-sn.get(i, 0))/(6*H.get(i+1).get(2)));
            S.set(i, 1,(sn.get(i,0))/2);
            S.set(i, 2,((dat.get(H.get(i+1).get(1).intValue())-dat.get(H.get(i).get(1).intValue()))/H.get(i+1).get(2))-
                    ((2*H.get(i+1).get(2)*sn.get(i,0)+H.get(i+1).get(2)*sn.get(i+1,0))/6));
            S.set(i, 3,(dat.get(H.get(i).get(1).intValue())));
        }


    }
    public void getResult(Vector<Double> dat)
    {
        result = new Vector<Double>();
        result=(Vector<Double>) dat.clone();
        for(int i=0;i<H.size();i++)
        {
            if(H.get(i).get(2)>1)
            {
                for(int ji=H.get(i).get(0).intValue();ji<H.get(i).get(1).intValue()-1;ji++)
                {
                    if(i!=0)
                    {result.setElementAt(
                            (S.get(i-1,0)*(Math.pow((ji+1)-H.get(i).get(0), 3.0)))+
                                    (S.get(i-1,1)*(Math.pow((ji+1)-H.get(i).get(0), 2.0)))+
                                    (S.get(i-1,2)*((ji+1)-H.get(i).get(0)))+S.get(i-1,3),ji+1);
                    }
                    else
                    {
                        result.setElementAt(
                                (S.get(i,0)*(Math.pow((ji+1)-H.get(i).get(0), 3.0)))+
                                        (S.get(i,1)*(Math.pow((ji+1)-H.get(i).get(0), 2.0)))+
                                        (S.get(i,2)*((ji+1)-H.get(i).get(0)))+S.get(i-1,3),ji+1);
                    }

                }
            }

        }
    }
    public void lastCero(SimpleMatrix mcero, SimpleMatrix m)
    {
        for(int lo=0;lo<mcero.numRows();lo++)
        {
            mcero.set(lo, mcero.numCols()-1, 0.0);
            mcero.set(mcero.numRows()-1, lo, 0.0);
        }
        for(int i=0;i<m.numRows();i++)
        {
            for(int j=0;j<m.numCols();j++)
            {
                mcero.set(i, j, m.get(i, j));
            }
        }
    }

    public SimpleMatrix arrayToSimpleM()
    {

        sm = new SimpleMatrix(coefmat.length,coefmat.length);

        for(int y=0;y<sm.numRows();y++)
        {


            for(int yq=0;yq<sm.numCols();yq++)
            {

                sm.set(y, yq, coefmat[y][yq]);

            }



        }
        return sm;
    }
    /*
    public static void main(String[] args) throws FileNotFoundException, IOException
    {
        readClassSerie fil= new readClassSerie();
        fil.readToVectFaltante("C:/Users/ALICIA/Favorites/Documents/NetBeansProjects/JavaApplication1/src/DataTest/2003/af.txt");
        fil.readToVect("C:/Users/ALICIA/Favorites/Documents/NetBeansProjects/JavaApplication1/src/DataTest/2003/a.txt");
        //System.out.println(fil.getSerief().size());


        cubicSplineH matH = new cubicSplineH();
        matH.genInterval(fil.getSerief());
        matH.initCoefMat();
        matH.fillCoefMat();
        matH.initYMat(fil.getSerief());

        for( Double[] row: matH.getCoefmat())
        {
        }
        matH.initSn();
        matH.initS(fil.getSerief());
        matH.getResult(fil.getSerief());
        System.out.println(matH.getResult());
        System.out.println(fil.getSerief());
        Double error=0.0;
        for(int o=0;o<fil.getSerief().size();o++)
        {
            error= error+ Math.pow(matH.getResult().get(o)-fil.getSerie().get(o),2.0);
        }
        System.out.println("mse : "+ Math.pow((matH.getResult().get(1)-fil.getSerie().get(2)),2.0));
        System.out.println("mse : "+error/matH.getResult().size());
        //


    } */

}
